/*
 * Copyright (C) 2013 Andreas Stuetz <andreas.stuetz@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.white.androidstudy.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.InputFilter;
import android.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;


import com.white.androidstudy.R;

import java.util.Locale;


/***
 * 顶部pager指示器
 */
public class PagerSlidingTabStrip extends HorizontalScrollView implements OnPageChangeListener
{

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
    {

    }

    @Override
    public void onPageSelected(int position)
    {

    }

    @Override
    public void onPageScrollStateChanged(int state)
    {

    }

    public interface IconTabProvider
    {
        public int getPageIconResId(int position);
    }

    // @formatter:off
    private static final int[] ATTRS = new int[]{
            android.R.attr.textSize,
            android.R.attr.textColor
    };
    // @formatter:on

    private LinearLayout.LayoutParams defaultTabLayoutParams;
    private LinearLayout.LayoutParams expandedTabLayoutParams;

    private final PageListener pageListener = new PageListener();
    public OnPageChangeListener delegatePageListener;

    private LinearLayout tabsContainer;
    private ViewPager pager;

    private int tabCount;

    private int currentPosition = 0;
    private float currentPositionOffset = 0f;

    private Paint indicatorPaint, underLinePaint;
    private int indicatorPadding;
    private Paint dividerPaint;

    private int indicatorColor = 0xEEFF0000;
    private int underlineColor = 0x33FFFFFF;
    private int dividerColor = 0xAAFF0000;

    private boolean shouldExpand = false;
    private boolean textAllCaps = true;

    private int scrollOffset = 52;
    private int indicatorHeight = 2;
    private int underlineHeight = 1;
    private RectF rectUnderline = new RectF();
    private int dividerPadding = 12;
    private int tabPadding = 24;
    private int dividerWidth = 1;

    private int tabTextSize = 30;
    private int selectTextSize = tabTextSize + 9;
    private int tabTextColor = 0xFF333333;
    private Typeface tabTypeface = null;
    private int tabTypefaceStyle = Typeface.BOLD;

    private int lastScrollX = 0;


    private Locale locale;

    private IndicatorLine indicatorLine;

    public PagerSlidingTabStrip(Context context)
    {
        this(context, null);
    }

    public PagerSlidingTabStrip(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);

        setFillViewport(true);
        setWillNotDraw(false);
        inflateAttributes(context, attrs);
        initPaint();
        createParent(context);
        setOnPageChangeListener(this);
        indicatorLine = new IndicatorLine();
    }

    private void inflateAttributes(Context context, AttributeSet attrs)
    {
        DisplayMetrics dm = getResources().getDisplayMetrics();

        scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
        indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm);
        underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm);
        dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm);
        tabPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm);
        dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm);
        tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, tabTextSize, dm);

        // get system attrs (android:textSize and android:textColor)

        TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);

        tabTextSize = a.getDimensionPixelSize(0, tabTextSize);
        selectTextSize = tabTextSize + 9;
        tabTextColor = a.getColor(1, tabTextColor);

        a.recycle();

        // get custom attrs

        a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);

        indicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, indicatorColor);
        underlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, underlineColor);
        dividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, dividerColor);
        indicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, indicatorHeight);
        underlineHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsUnderlineHeight, underlineHeight);
        dividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerPadding, dividerPadding);
        tabPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, tabPadding);
        shouldExpand = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, shouldExpand);
        scrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsScrollOffset, scrollOffset);
        textAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps);

        a.recycle();
    }

    private void initPaint()
    {
        indicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        indicatorPaint.setStyle(Style.FILL);
        indicatorPaint.setColor(indicatorColor);

        underLinePaint = new Paint();
        underLinePaint.setStyle(Style.FILL);
        underLinePaint.setColor(underlineColor);

        dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        dividerPaint.setStrokeWidth(dividerWidth);

        defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f);

        if (locale == null)
        {
            locale = getResources().getConfiguration().locale;
        }
    }


    private void createParent(Context context)
    {
        tabsContainer = new LinearLayout(context);
        tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
        tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        addView(tabsContainer);
    }

    public void setViewPager(ViewPager pager)
    {
        this.pager = pager;

        if (pager.getAdapter() == null)
        {
            throw new IllegalStateException("ViewPager does not have adapter instance.");
        }

        pager.addOnPageChangeListener(pageListener);
        pager.addOnPageChangeListener(this);
        notifyDataSetChanged();
    }

    public void setOnPageChangeListener(OnPageChangeListener listener)
    {
        this.delegatePageListener = listener;
    }

    public void notifyDataSetChanged()
    {

        tabsContainer.removeAllViews();

        tabCount = pager.getAdapter().getCount();
        if (tabCount <= 5)
        {
            shouldExpand = true;
        }
        for (int i = 0; i < tabCount; i++)
        {
            if (TextUtils.isEmpty(pager.getAdapter().getPageTitle(i)))
                throw new IllegalStateException("The mothod 'getPageTitle' seems not to be implemented");
            addTextTab(i, pager.getAdapter().getPageTitle(i).toString());
        }

        updateTabStyles();

        getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
        {

            @SuppressWarnings("deprecation")
            @SuppressLint("NewApi")
            @Override
            public void onGlobalLayout()
            {

                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
                {
                    getViewTreeObserver().removeGlobalOnLayoutListener(this);
                } else
                {
                    getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }

                currentPosition = pager.getCurrentItem();
                scrollToChild(currentPosition, 0);
            }
        });

    }

    private void addTextTab(final int position, String title)
    {
        TextView tab = new TextView(getContext());
        tab.setText(title);
        tab.setGravity(Gravity.CENTER);
        tab.setSingleLine();
        //当自适应宽度的时候
        if(shouldExpand)
        {
            InputFilter[] i = new InputFilter[]{new InputFilter.LengthFilter(5)};
            tab.setFilters(i);
            tab.setEllipsize(TextUtils.TruncateAt.END);
        }
        addTab(position, tab);
    }

    private void addTab(final int position, View tab)
    {
        tab.setFocusable(true);
        tab.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                pager.setCurrentItem(position);
            }
        });
        if (!shouldExpand)
        {
            tab.setPadding(tabPadding, 0, tabPadding, 0);
        }
        tabsContainer.addView(tab, position, shouldExpand ? expandedTabLayoutParams : defaultTabLayoutParams);
    }

    private void updateTabStyles()
    {

        int currentSelect = pager.getCurrentItem();
        for (int i = 0; i < tabCount; i++)
        {

            View v = tabsContainer.getChildAt(i);

            if (v instanceof TextView)
            {
                TextView tab = (TextView) v;
                tab.setTypeface(tabTypeface, tabTypefaceStyle);
                if (currentSelect == i)
                {
                    tab.setTextColor(indicatorColor);
                    tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize);
                } else
                {
                    tab.setTextColor(tabTextColor);
                    tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize);
                }
                // setAllCaps() is only available from API 14, so the upper case is made manually if we are on a
                // pre-ICS-build
                if (textAllCaps)
                {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
                    {
                        tab.setAllCaps(true);
                    } else
                    {
                        tab.setText(tab.getText().toString().toUpperCase(locale));
                    }
                }
            }
        }

    }

    private void scrollToChild(int position, int offset)
    {

        if (tabCount == 0)
        {
            return;
        }

        int newScrollX = tabsContainer.getChildAt(position).getLeft() + offset;

        if (position > 0 || offset > 0)
        {
            newScrollX -= scrollOffset;
        }

        if (newScrollX != lastScrollX)
        {
            lastScrollX = newScrollX;
            scrollTo(newScrollX, 0);
        }
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        if (isInEditMode() || tabCount == 0)
        {
            return;
        }

        //画选中的item的下划线
        drawIndicatorLine(canvas);

        // 画最底下的线
        drawUnderline(canvas);

        // draw divider
        drawVerticalDivider(canvas);
    }

    private void drawIndicatorLine(Canvas canvas)
    {
        if (!disAllowInidicator)
        {
            indicatorPaint.setColor(indicatorColor);
            rectUnderline.left = indicatorLine.left;
            rectUnderline.top = height - indicatorHeight;
            rectUnderline.right = indicatorLine.right;
            rectUnderline.bottom = height;
            canvas.drawRoundRect(rectUnderline, indicatorHeight / 2f, indicatorHeight / 2f, indicatorPaint);
        }
    }

    private void drawUnderline(Canvas canvas)
    {
        if (!disAllowUnderline)
        {
            underLinePaint.setColor(underlineColor);
            canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, underLinePaint);
        }
    }

    private void drawVerticalDivider(Canvas canvas)
    {
        if (!disAllowDivider)
        {
            dividerPaint.setColor(dividerColor);
            for (int i = 0; i < tabCount - 1; i++)
            {
                View tab = tabsContainer.getChildAt(i);
                canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
            }
        }
    }

    private boolean disAllowInidicator;
    private boolean disAllowUnderline = true;
    private boolean disAllowDivider = true;

    public void setDisallowDrawIndicator(boolean yn)
    {
        this.disAllowInidicator = yn;
        requestLayout();
    }

    public void setDisAllowUnderline(boolean yn)
    {
        this.disAllowUnderline = yn;
        requestLayout();
    }

    public void setDisallowDivider(boolean yn)
    {
        this.disAllowDivider = yn;
        requestLayout();
    }


    private int height;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        height = getMeasuredHeight();
    }

    private int lastPosition;
    private static final int SLIDING_RIGHT = 5;
    private static final int SLIDING_LEFT = 6;
    private int slidingDerection;

    private class PageListener implements OnPageChangeListener
    {

        View currentTab;
        View nextTab;

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
        {
            Log.e("s", "position = " + position + "--" + "positionOffset=" + positionOffset + "--positionOffsetPixels=" + positionOffsetPixels);

            //像右边滑动时，position是当前位置，像左边滑动时是将要滑到的位置
            currentPosition = position;
            currentPositionOffset = positionOffset;

            currentTab = tabsContainer.getChildAt(position);

            Log.e("s", "lastPosition = " + lastPosition + "--- position = " + position);
            if (position >= lastPosition)//向右
            {
                Log.e("s", "向右");
                if (position < tabsContainer.getChildCount() - 1)
                {
                    nextTab = tabsContainer.getChildAt(position + 1);
                }
                if (position < tabsContainer.getChildCount() - 1)
                {
                    slidingDerection = SLIDING_RIGHT;

                    //渐变颜色

                    TextView forwad = (TextView) tabsContainer.getChildAt(position + 1);
                    TextView current = (TextView) tabsContainer.getChildAt(position);
                    forwad.setTextColor(evaluate(positionOffset, tabTextColor, indicatorColor));
                    current.setTextColor(evaluate(positionOffset, indicatorColor, tabTextColor));

                }
            } else//向左
            {

                nextTab = tabsContainer.getChildAt(position + 1);
                slidingDerection = SLIDING_LEFT;


                TextView forwad = (TextView) tabsContainer.getChildAt(position);
                TextView current = (TextView) tabsContainer.getChildAt(position + 1);
                forwad.setTextColor(evaluate(positionOffset, indicatorColor, tabTextColor));
                current.setTextColor(evaluate(positionOffset, tabTextColor, indicatorColor));

            }

            //超过显示区域才会看到效果
            scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));

            if (delegatePageListener != null)
            {
                delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }

            calcPosition();
            invalidate();
        }

        private void calcPosition()
        {
            TextView c = (TextView) currentTab;
            String cstr = c.getText().toString();
            int end = cstr.length();
            Rect cr = new Rect();
            c.getPaint().getTextBounds(cstr, 0, end, cr);

            TextView n = (TextView) nextTab;
            String nstr = n.getText().toString();
            end = nstr.length();
            Rect nr = new Rect();
            n.getPaint().getTextBounds(nstr, 0, end, nr);


            indicatorLine.left = c.getLeft() + c.getMeasuredWidth()/2 - cr.width()/2;
            indicatorLine.right = indicatorLine.left + cr.width();
            final float nextTabLeft = n.getLeft() + n.getMeasuredWidth()/2 - nr.width()/2;
            final float nextTabRight = nextTabLeft + nr.width();
            indicatorLine.left = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * indicatorLine.left);
            indicatorLine.right = currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * indicatorLine.right;
        }

        @Override
        public void onPageScrollStateChanged(int state)
        {
            if (state == ViewPager.SCROLL_STATE_IDLE)
            {
                scrollToChild(pager.getCurrentItem(), 0);
                lastPosition = pager.getCurrentItem();
            }
            if (delegatePageListener != null)
            {
                delegatePageListener.onPageScrollStateChanged(state);
            }
        }

        @Override
        public void onPageSelected(int position)
        {
            if (delegatePageListener != null)
            {
                delegatePageListener.onPageSelected(position);
            }
        }

    }

    private void toLeftSizeChange(TextView forwad, TextView current)
    {
        float v = 0;
        float csize = selectTextSize * v + (1 - v) * tabTextSize;
        float fsize = tabTextSize * v + (1 - v) * selectTextSize;
        forwad.setTextSize(TypedValue.COMPLEX_UNIT_PX, fsize);
        current.setTextSize(TypedValue.COMPLEX_UNIT_PX, csize);
    }

    private void toRightSizeChange(TextView forwad, TextView current)
    {
        float v = 0;
        float fsize = selectTextSize * v + (1 - v) * tabTextSize;
        float csize = tabTextSize * v + (1 - v) * selectTextSize;
        forwad.setTextSize(TypedValue.COMPLEX_UNIT_PX, fsize);
        current.setTextSize(TypedValue.COMPLEX_UNIT_PX, csize);
    }

    /***
     * 颜色渐变
     * @param fraction 比例因子0-1
     * @param startValue 当前颜色
     * @param endValue    目的颜色
     * @return
     */
    public int evaluate(float fraction, int startValue, int endValue)
    {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;

        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;

        return (int) ((startA + (int) (fraction * (endA - startA))) << 24) |
                (int) ((startR + (int) (fraction * (endR - startR))) << 16) |
                (int) ((startG + (int) (fraction * (endG - startG))) << 8) |
                (int) ((startB + (int) (fraction * (endB - startB))));
    }

    public void setIndicatorColor(int indicatorColor)
    {
        this.indicatorColor = indicatorColor;
    }

    public void setIndicatorColorResource(int resId)
    {
        this.indicatorColor = getResources().getColor(resId);
        invalidate();
    }


    public void setIndicatorHeight(int indicatorLineHeightPx)
    {
        this.indicatorHeight = indicatorLineHeightPx;
        invalidate();
    }

    public void setUnderlineColor(int underlineColor)
    {
        this.underlineColor = underlineColor;
        invalidate();
    }

    public void setUnderlineColorResource(int resId)
    {
        this.underlineColor = getResources().getColor(resId);
        invalidate();
    }


    public void setDividerColor(int dividerColor)
    {
        this.dividerColor = dividerColor;
        invalidate();
    }

    public void setDividerColorResource(int resId)
    {
        this.dividerColor = getResources().getColor(resId);
        invalidate();
    }

    public void setDividerPadding(int dividerPaddingPx)
    {
        this.dividerPadding = dividerPaddingPx;
        invalidate();
    }


    public void setShouldExpand(boolean shouldExpand)
    {
        this.shouldExpand = shouldExpand;
        requestLayout();
    }

    public void setTextSize(int textSizePx)
    {
        this.tabTextSize = textSizePx;
        selectTextSize = tabTextSize + 9;
        updateTabStyles();
    }

    public int getTextSize()
    {
        return tabTextSize;
    }

    public void setTextColorResource(int resId)
    {
        this.tabTextColor = getResources().getColor(resId);
        updateTabStyles();
    }


    public void setTypeface(Typeface typeface, int style)
    {
        this.tabTypeface = typeface;
        this.tabTypefaceStyle = style;
        updateTabStyles();
    }

    class IndicatorLine
    {
        public float left;
        public float right;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state)
    {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        currentPosition = savedState.currentPosition;
        requestLayout();
    }

    @Override
    public Parcelable onSaveInstanceState()
    {
        Parcelable superState = super.onSaveInstanceState();
        SavedState savedState = new SavedState(superState);
        savedState.currentPosition = currentPosition;
        return savedState;
    }

    static class SavedState extends BaseSavedState
    {
        int currentPosition;

        public SavedState(Parcelable superState)
        {
            super(superState);
        }

        private SavedState(Parcel in)
        {
            super(in);
            currentPosition = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel dest, int flags)
        {
            super.writeToParcel(dest, flags);
            dest.writeInt(currentPosition);
        }

        public static final Creator<SavedState> CREATOR = new Creator<SavedState>()
        {
            @Override
            public SavedState createFromParcel(Parcel in)
            {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size)
            {
                return new SavedState[size];
            }
        };
    }

}
